/*
 * IMRoutingM.nc -- routing component
 *
 * Copyright (C) Andrey Vihrov <andrey.vihrov@gmail.com>, 2010
 * Copyright (C) Askar Salimbaev <ghostinshell@gmail.com>, 2010
 *
 * This file is part of Intermote.
 *
 * Intermote is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Intermote is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Intermote.  If not, see <http://www.gnu.org/licenses/>.
 */

module IMRoutingM {

	provides {
		interface Packet;

		interface AMSend[im_rt_id_t id];
		interface Receive[im_rt_id_t id];
	}

	uses {
		interface Packet as ProtocolPacket;
		interface AMSend as ProtocolSend;
		interface Receive as ProtocolReceive;
	}

}
implementation {

	/**
	 * Routing packet contents
	 */
	typedef nx_struct {
		nx_struct rt_headers {
			nx_uint8_t  id;
		} headers;

		nx_uint8_t  data[];
	} RoutingPacket;
	#define RT_HDR_SIZE sizeof(nx_struct rt_headers)


	/* Packet interface operations */

	command void Packet.clear (message_t *msg)
	{
		call ProtocolPacket.clear(msg);
	}

	command uint8_t Packet.payloadLength (message_t *msg)
	{
		return call ProtocolPacket.payloadLength(msg) - RT_HDR_SIZE;
	}

	command void Packet.setPayloadLength (message_t *msg, uint8_t len)
	{
		call ProtocolPacket.setPayloadLength(msg, len + RT_HDR_SIZE);
	}

	command uint8_t Packet.maxPayloadLength (void)
	{
		return call ProtocolPacket.maxPayloadLength() - RT_HDR_SIZE;
	}

	command void *Packet.getPayload (message_t *msg, uint8_t len)
	{
		RoutingPacket *pack = call ProtocolPacket.getPayload(msg, len + RT_HDR_SIZE);

		if (pack)
			return pack->data;
		else
			return NULL;
	}


	/* AMSend interface operations */

	command error_t AMSend.send[im_rt_id_t id] (am_addr_t addr, message_t *msg, uint8_t len)
	{
		RoutingPacket *pack = call ProtocolPacket.getPayload(msg, len + RT_HDR_SIZE);

		if (!pack)
			return FAIL;

		pack->headers.id = id;

		return call ProtocolSend.send(addr, msg, len + RT_HDR_SIZE);
	}

	command error_t AMSend.cancel[im_rt_id_t id] (message_t *msg)
	{
		return call ProtocolSend.cancel(msg);
	}

	event void ProtocolSend.sendDone (message_t *msg, error_t err)
	{
		RoutingPacket *pack = call ProtocolPacket.getPayload(msg, call ProtocolPacket.payloadLength(msg));

		if (!pack)
			return;
		else
			signal AMSend.sendDone[pack->headers.id](msg, err);
	}

	command uint8_t AMSend.maxPayloadLength[im_rt_id_t id] (void)
	{
		return call Packet.maxPayloadLength();
	}

	command void *AMSend.getPayload[im_rt_id_t id] (message_t *msg, uint8_t len)
	{
		return call Packet.getPayload(msg, len);
	}

	default event void AMSend.sendDone[im_rt_id_t id] (message_t *msg, error_t err)
	{

	}


	/* Receive interface operations */

	event message_t *ProtocolReceive.receive (message_t *msg, void *payload, uint8_t len)
	{
		RoutingPacket *pack = payload;

		if (len < RT_HDR_SIZE)
			return msg;

		return signal Receive.receive[pack->headers.id](msg, pack->data, len - RT_HDR_SIZE);
	}

	default event message_t *Receive.receive[im_rt_id_t] (message_t *msg, void *payload, uint8_t len)
	{
		return msg;
	}

}
